peforth magic command on jupyter notebook

peforth supports jupyter notebook magic command %f since v1.15 (released to Pypi on 2018.3.12) with both line magic and cell magic.

If you are running this jupyter notebook page online through mybinder.org then no installation is needed.

If you would like to work on your computer, so you can save changes you made, then pip install peforth to install peforth and that's all, assume you already have jupyter notebook installed.

1. import peforth $^i$

peforth magics are unknown to jupyter notebook at first untill we import peforth.


In [1]:
import peforth


reDef unknown

2. Hello World!

Here after, in any python code cell, a %f leading line is interpreted as a FORTH line, called line magic. The next cell is an example of the version command that shows peforth greeting message and leaves the version number on the data stack.


In [2]:
%f version .s


p e f o r t h    v1.23
source code http://github.com/hcchengithub/peforth
Type 'peforth.ok()' to enter forth interpreter, 'exit' to come back.

      0: 1.23 (<class 'str'>)

In [3]:
%f ." Hello World!" cr


Hello World!

The amazing thing here is that the %f line magic can be used in python code. . .


In [4]:
# use %f line magic in a python code function definition,
def hi():
    %f ." Hello World!" cr

# believe it or not, it works!
hi()


Hello World!

3. line magic is compiled to a python statement

Now use peforth command .source to find out why this is possible . . .


In [5]:
%f __main__ :> hi .source


def hi():
    get_ipython().run_line_magic('f', '." Hello World!" cr')

The %f line magic is compiled into a python statement, that's why. Some more explanations given at the end of this page.

4. peforth %%f cell magic

A cell leading with a %%f (double %% instead of single % in line magic form) becomes a block of FORTH code.


In [6]:
%%f Nothing allowed before %%f except white spaces; everything in this line after %%f is ignored.

\ Demonstrating the peforth interpret mode [for]..[next] loop

5 [for] t@ . space [next] cr

\ For experienced FORTH users
\ Where t@ is like the FORTH word r@ but it fetches TIB stack instead of the traditional 
\ FORTH return stack. Because TIB is the only resource that belongs to this interpreting 
\ life cycle alone.


5 4 3 2 1 

Now use the [for] loop to print a pyramid:


In [7]:
%%f
: star ." *" ;
: 2stars star star ;
: stars for star next ;
star cr 2stars cr 10 [for] 13 t@ - stars cr [next]


*
**
***
****
*****
******
*******
********
*********
**********
***********
************

5. peforth to access the main name space directly

Peforth and the Jupyter Notebook are of different name spaces, meaning that peforth can't see the x variable in the example below:


In [8]:
x = 123
%f x . cr


123

The reason why we choose FORTH is for its super flexibility. Now let's redefine the way peforth handles an unknown token, i.e. the x of the above example. Instead of alerting "Error! x unknown." we let it try to find the token in the Jupyter Notebook __main__ module object.

Note: peforth v1.16 and newer version is required to play this trick. Since v1.23 the 'unknown' introduced below has become a built-in so we don't need the re-definition. Instead, use marker command '===' to forget it so the 'x' would be an 'unknown' again.


In [9]:
%%f   Now we redefine the 'unknown' command (it does nothing by default)

: unknown // ( token -- thing y|n) Try to find the unknown token in __main__
  py> getattr(sys.modules['__main__'],pop(),"Ûnknôwn") 
  py> str(tos())=="Ûnknôwn" if drop false else true then ;
    
\ here after, when FORTH come accross an unknown token, instead of printing the
\ error message, it try to find the token in python __main__ module name space.


reDef unknown

now test again:


In [10]:
y = 'abc'
%f y . cr
%f x . cr


abc
123

peforth seems know the 'x' and 'y' now while it doesn't. This trick is vary useful when we are studying and we can investigate things in FORTH way.

5. So where is the muggle FORTH that works as a REPL shell environment?

peforth.ok() is the peforth interpreter itself. Run peforth.ok() to shell a level of the FORTH interpreter and exit command to come back.


In [11]:
# Run this cell to enter peforth console (REPL loop or command line interface)
# Note the Out[ ] of this cell, the `[*]` indicates that the command line interface
# is running. Play with it or copy-paste this line: 
#     "star cr 2stars cr 10 [for] 13 t@ - stars cr [next] exit"
# to try again the pyramid example above. 'exit' command to terminate.
peforth.ok()


star cr 2stars cr 10 [for] 13 t@ - stars cr [next] exit
*
**
***
****
*****
******
*******
********
*********
**********
***********
************
OK 
Out[11]:
<module 'peforth.projectk' from 'c:\\users\\hcche\\appdata\\local\\programs\\python\\python36\\lib\\site-packages\\peforth\\projectk.py'>

6. Cascading peforth exported functions

%f and %%f magics are actually performing the peforth.dictate('command lines') exported function, while peforth.ok() is the REPL loop of the same function. Try:

peforth.dictate(" .' hello world!' cr ") 

that works exactly as we have tried at first.


In [12]:
peforth.dictate(" .' hello world!' cr ")  # Note the Out[ ] of this cell


hello world!
Out[12]:
<module 'peforth.projectk' from 'c:\\users\\hcche\\appdata\\local\\programs\\python\\python36\\lib\\site-packages\\peforth\\projectk.py'>

Observed from the above outputs, peforth.ok() and peforth.dictate() both return the peforth module object. This means that we can cascade these functions. The next example sees the type of the 'star' command that we definded above:


In [13]:
%%f
' star   \ get the word object, we defined 'star' above remember?
:> type  \ get 'type' attribute of the word object
. cr     \ show what we have got ... it is a 'colon' word, isn't it?


colon

It's correctly a 'colon' word. The next example in python code is actually doing the same thing as the above FORTH code:


In [14]:
# Example of cascaded functions, to check a given FORTH word's type  

type_of_star = peforth.push('star').dictate("(') :> type").pop() # cascaded functions 
print(type_of_star)


colon

Where (') and :> are peforth words explained by help command as shown below. Function cascading is very useful for peforth to debug or to investigate your python target code.

Peforth functions that can be called cascadedly are: peforth.ok(), peforth.dictate() , peforth.push() and peforth.execute().


In [15]:
%f help (')


( "name" -- Word ) name>Word like tick but the name is from TOS.


In [16]:
%f help :>


( obj <sub-statement> -- value ) Simplified form of "obj py> pop().foo.bar" w/return value
	down to the next whitespace

More information about peforth are on the wiki of the project on Github.

May the FORTH be with you!

H.C. Chen @ FigTaiwan
Last Edited: 2018.6.27


Notes

i. The ipython setting to automatically load peforth %f magic

Optionally if you want ipython to load %f magic automatically at startup of every jupyter notebook, so you don't need to import peforth explicitly everytime, what you need to do is to make . . .

this config file:

C:\Users\<your user name>\.ipython\profile_default\ipython_config.py (for Windows)
or
~/.ipython/profile_default/ipython_config.py (for Linux) 

this line:

# A list of dotted module names of IPython extensions to load.
c.InteractiveShellApp.extensions = ['peforth']

to have 'peforth' in the list as shown above.

ii. A line magic command line compiled to python statement

__main__ is a peforth word that returns the main program module object which in the current case is this jupyter notebook. __main__ is the parent module of the funcion hi() and __main__ :> hi is the way peforth gets the hi function object. Finally .source displays the source code on top of the FORTH data stack which is now the hi function object. So this line magic:

%f __main__ :> hi cr

is compiled to:

get_ipython().run_line_magic('f', '." Hello World!" cr')

Where 'f' is apparently the peforth magic command's name.

--- The End ---